// SPDX-License-Identifier: GPL-2.0
/******************************************************************************
 *    NAND Flash Controller V301 Device Driver
 *    Copyright (c) 2009-2010 by Hisilicon.
 *    All rights reserved.
 * ***
 *
 ******************************************************************************/

#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/rawnand.h>
#include <linux/mtd/partitions.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <asm/errno.h>
#include <linux/platform_device.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>

#include "mtdcore.h"
#include "hifmcv100.h"

static const char * const ecctype_5117_string[] = {"None", "8bit", "16bit", "24bit",
	"28bit", "40bit", "64bit"};
static const char * const pagesize_str[] = {"2K", "4K", "8K", "unknown"};
static struct fmc_block_status_info g_dfx_blcok_status;

static const char *get_ecctype_str(int ecctype)
{
	return ecctype_5117_string[((unsigned int)ecctype & 0x0F)];
}

static const char *get_pagesize_str(enum page_fmc_type pagetype)
{
	return pagesize_str[pagetype];
}

static unsigned int get_pagesize(enum page_fmc_type pagetype)
{
	unsigned int pagesize[] = { FMC_2K, FMC_4K, FMC_8K, FMC_16K};
	return pagesize[pagetype];
}

static unsigned int get_blocksize(enum block_fmc_type blocktype)
{
	unsigned int blocksize[] = {64, 128, 256, 512};
	return blocksize[blocktype];
}

static void fmc_dma_transfer(struct hinfc_host *host, int todev)
{
	unsigned int reg_val = 0;

	/* CPU configures the address for reading and writing data in DDR */
	/* DMA operates DDR`s register which named head-address 0 register */
	hinfc_write(host, host->dma_buffer, FMC_DMA_SADDR_D0);

	/* DMA operates the DDR`s head-address register which used for saving OOB */
	hinfc_write(host, host->dma_oob, FMC_DMA_SADDR_OOB);

	/*
	 * You can use DMA for none-ECC operation,which compared to open ECC,
	 * the operation is almost same,but ECC0 needs to configure the FMC_DMA_LAN
	 * register according to the length of other message except those information
	 * (ECC code and OOB data),the maximum length equal to the length of space.
	 * ECC0 way is almost used in debugging,but ECC0 does not support CACHE read
	 * and block read
	 */
	if (host->ecctype == et_ecc_5117_none) {
		/*
		 * DMA operation length register: DMA operation data handling length, in bytes.
		 * For spi NAND ecc0 and NAND ecc0, configured as spare area data length
		 */
		hinfc_write(host,
			(host->oobsize & FMC_DMA_LEN_OOB_MASK),
			FMC_DMA_LEN);
	}

	if (todev) {
		hinfc_write(host,
			(((host->chipselect & FMC_OP_CFG_CS_MASK) << FMC_OP_CFG_CS_SHIFT) |
			((host->opcode.wr_code.if_type &
				FMC_OP_CFG_IF_TYPE_MASK) << FMC_OP_CFG_IF_TYPE_SHIFT) |
			(host->opcode.wr_code.dummy & FMC_OP_CFG_DUMMY_NUM_MASK)),
			FMC_OP_CFG);
		reg_val = FMC_OP_CTRL_DMA_OP_READY | FMC_OP_CTRL_RW_OP |
			(host->opcode.wr_code.opcode &
				FMC_OP_CTRL_WR_OPCODE_MASK) << FMC_OP_CTRL_WR_OPCODE_SHIFT;
	} else {
		/*
		 * the NAND FLASH device operated by DMA
		 * which is used for operating configure register
		 */
		hinfc_write(host,
			(((host->chipselect & FMC_OP_CFG_CS_MASK) << FMC_OP_CFG_CS_SHIFT) |
			((host->opcode.rd_code.if_type &
				FMC_OP_CFG_IF_TYPE_MASK) << FMC_OP_CFG_IF_TYPE_SHIFT) |
			(host->opcode.rd_code.dummy & FMC_OP_CFG_DUMMY_NUM_MASK)),
			FMC_OP_CFG);
		/*
		 * when CPU writes in FMC_OP_CTRL register, set the status
		 * of rw_op is read(the value equal to 0),the operate way
		 * is dma if finish those configure,then set FMC_OP_CTRL[0]
		 * equal to 1,make FMC reading FLASH
		 */
		reg_val = FMC_OP_CTRL_DMA_OP_READY |
			(host->opcode.rd_code.opcode &
				FMC_OP_CTRL_RD_OPCODE_MASK) << FMC_OP_CTRL_RD_OPCODE_SHIFT;
	}

	wmb(); /* add barrier before writing data to host */

	/*
	 * operate control register:spi nand/nor flash,
	 * not bus way, but DMA read/write for operating
	 */
	hinfc_write(host, reg_val, FMC_OP_CTRL);

	/*
	 * when dma starts to read this bit and return 0,
	 * which means dma is end,then confirm it is normal by chip view
	 */
	hi_reg_status_check(host, FMC_OP_CTRL);
}

void hi_fmc_ecctype_set(struct hinfc_host *host, unsigned int ecc_value)
{
	unsigned int reg_value;

	/* device-configure register,set the type of controller`s ecc */
	reg_value = hinfc_read(host, FMC_CFG);
	reg_value &= ~0xe0;
	reg_value |= (ecc_value & FMC_CFG_ECCTYPE_MASK) << FMC_CFG_ECCTYPE_SHIFT;

	hinfc_write(host, reg_value, FMC_CFG);
}

int hi_fmc_ecctype_get(struct hinfc_host *host)
{
	unsigned int reg_value;

	/* device-configure register,get the type of controller's ecc */
	reg_value = hinfc_read(host, FMC_CFG);

	return (reg_value >> FMC_CFG_ECCTYPE_SHIFT) & FMC_CFG_ECCTYPE_MASK;
}

void hi_fmc_wren(struct hinfc_host *host)
{
	if (host->flashtype == NAND_FLASH_TYPE)
		return;

	/* Command word configuration register */
	hinfc_write(host, FMC_CMD_WRITE_ENABLE, FMC_CMD);

	/* the NAND FLASH device operated by DMA which is used for operating configure register */
	hinfc_write(host,
		(host->chipselect & FMC_OP_CFG_CS_MASK) << FMC_OP_CFG_CS_SHIFT, FMC_OP_CFG);

	/* operate register:logic for enable&send command1 for enable to flash */
	hinfc_write(host, FMC_OP_REG_OP_START|FMC_OP_CMD1_EN, FMC_OP);

	/* Whether the logic is completed */
	hi_reg_status_check(host, FMC_OP);
}

void hi_fmc_set_feature(
	struct nand_chip *chip, unsigned int reg, unsigned int value, unsigned int cmd)
{
	unsigned int ecc_type;
	struct hinfc_host *host = (struct hinfc_host *)chip->priv;

	hi_fmc_wren(host);

	ecc_type = hi_fmc_ecctype_get(host);
	hi_fmc_ecctype_set(host, 0); /* without ECC */

	/* Command word configuration register */
	hinfc_write(host, cmd, FMC_CMD);

	/* set high bit of register by the address of device */
	hinfc_write(host, 0, FMC_ADDRH);

	/* set low 4 bits of register by the address of device */
	hinfc_write(host, reg, FMC_ADDRL);

	/*
	 * the NAND FLASH device operated by DMA which is used for operating configure register,
	 * Number of Bytes sent to Flash
	 */
	hinfc_write(host,
		(host->chipselect & FMC_OP_CFG_CS_MASK) << FMC_OP_CFG_CS_SHIFT |
		(1 & FMC_OP_CFG_ADDR_NUM_MASK) << FMC_OP_CFG_ADDR_NUM_SHIFT,
		FMC_OP_CFG);

	if (host->flashtype == SPI_NAND_FLASH_TYPE)
		hinfc_write(host, 0x1, FMC_DATA_NUM);
	else if (host->flashtype == NAND_FLASH_TYPE)
		hinfc_write(host, 0x4, FMC_DATA_NUM); /* data-length register */

	*((unsigned int *)chip->legacy.IO_ADDR_W) = value;

	if (host->flashtype == SPI_NAND_FLASH_TYPE) {
		hinfc_write(host,
			FMC_OP_REG_OP_START | FMC_OP_WRITE_DATA_EN |
			FMC_OP_ADDR_EN | FMC_OP_CMD1_EN,
			FMC_OP);
	} else if (host->flashtype == NAND_FLASH_TYPE) {
		/*
		 * when operating register,nand flash needs to
		 * wait the signal of ready/busy to turn up for enable
		 * send command1 for enable to flash
		 * write operated address for enable to FLASH
		 * write data for enable to FLash
		 */
		hinfc_write(host,
			FMC_OP_REG_OP_START |
			FMC_OP_WAIT_READY_EN |
			FMC_OP_WRITE_DATA_EN |
			FMC_OP_ADDR_EN |
			FMC_OP_CMD1_EN, FMC_OP);
	}

	hi_reg_status_check(host, FMC_OP);
	hi_fmc_ecctype_set(host, ecc_type);
}

unsigned int hi_fmc_get_feature(struct nand_chip *chip, unsigned int reg, unsigned int cmd)
{
	unsigned int reg_value;
	unsigned int ecc_type;
	struct hinfc_host *host = chip->priv;

	ecc_type = hi_fmc_ecctype_get(host);
	hi_fmc_ecctype_set(host, 0); /* without ECC */
	hinfc_write(host, cmd, FMC_CMD);
	hinfc_write(host, 0, FMC_ADDRH);
	hinfc_write(host, reg, FMC_ADDRL);
	hinfc_write(host,
		(host->chipselect & FMC_OP_CFG_CS_MASK) << FMC_OP_CFG_CS_SHIFT |
		(1 & FMC_OP_CFG_ADDR_NUM_MASK) << FMC_OP_CFG_ADDR_NUM_SHIFT,
		FMC_OP_CFG);

	if (host->flashtype == SPI_NAND_FLASH_TYPE) {
		hinfc_write(host, 0x1, FMC_DATA_NUM);
		hinfc_write(host,
			FMC_OP_REG_OP_START | FMC_OP_READ_DATA_EN | FMC_OP_ADDR_EN | FMC_OP_CMD1_EN,
			FMC_OP);
	} else {
		hinfc_write(host, 0x4, FMC_DATA_NUM);  /* data-length register */
		/*
		 * logic for enable
		 * enable to read from FLash
		 * nand flash needs to wait for signal of ready/busy up for enable
		 * write operated address for enable to FLASH
		 * send command1 for enable to flash
		 */
		hinfc_write(host,
			FMC_OP_REG_OP_START |
			FMC_OP_READ_DATA_EN |
			FMC_OP_WAIT_READY_EN |
			FMC_OP_ADDR_EN |
			FMC_OP_CMD1_EN, FMC_OP);
	}

	hi_reg_status_check(host, FMC_OP);
	hi_fmc_ecctype_set(host, ecc_type);
	reg_value = *((unsigned int *)chip->legacy.IO_ADDR_R);

	return reg_value;
}

void hi_fmc_dieid_set(struct hinfc_host *host, unsigned int die_id)
{
	/*
	 * if value of die_num is less than 2, it indicates that the
	 * flash is no initialized or is not a winbond 2 gig flash,
	 * no need to set, return imediately
	 */
	if (host->opcode.die_code.die_num < 2)
		return;

	/*
	 * winbond W25M02GV flashhas 2 1 gig spi_nand_flash,
	 * different areas controlled by die id
	 */
	hinfc_write(host, (die_id << 8) | (host->opcode.die_code.die_cmd), FMC_CMD);
	hinfc_write(host, (host->chipselect &
			FMC_OP_CFG_CS_MASK) << FMC_OP_CFG_CS_SHIFT, FMC_OP_CFG);
	hinfc_write(host, FMC_OP_REG_OP_START | FMC_OP_CMD1_EN | FMC_OP_CMD2_EN, FMC_OP);
	/*
	 * operation done, prepared for next command.
	 * can only set to 0, indicating that logic is complete
	 */
	hi_reg_status_check(host, FMC_OP);
}

int fmc_flash_feature_init(struct mtd_info *mtd)
{
	unsigned int reg_value;
	unsigned int die_id;
	unsigned int temp = 0;
	struct nand_chip *chip = mtd_to_nand(mtd);
	struct hinfc_host *host = chip->priv;

	if (host->flashtype == SPI_NAND_FLASH_TYPE) {
		/*
		 * this function will only be performed after flash_type init,
		 * in this case, host->opcode.die_code.die_num is initialized
		 */
		die_id = 0;
		temp = 1;
		if (host->opcode.die_code.die_num > 1)
			temp = host->opcode.die_code.die_num;

		do {
			hi_fmc_dieid_set(host, die_id);
			reg_value = hi_fmc_get_feature(chip,
				SPI_NAND_BLOCK_PROTECTION_REGISTER, FMC_CMD_GET_FEATURE);
			reg_value &= ~0x78; /* PROTECTION_REGISTER leftmost bit valid */
			hi_fmc_set_feature(chip,
				SPI_NAND_BLOCK_PROTECTION_REGISTER, reg_value, FMC_CMD_SET_FEATURE);
			reg_value = hi_fmc_get_feature(chip,
				SPI_NAND_SECURE_OTP_REGISTER, FMC_CMD_GET_FEATURE);
			reg_value &= ~0x10; /* OTP_REGISTER reg_value get least 7 bits */

			/* config CFG0 bit based on if_type */
			if (host->opcode.rd_code.if_type > 2)
				reg_value |= 0x1;
			else
				reg_value &= ~0x1;
			hi_fmc_set_feature(chip,
				SPI_NAND_SECURE_OTP_REGISTER, reg_value, FMC_CMD_SET_FEATURE);
			die_id++;
		} while (die_id < temp);
	}

	return 0;
}

int hifmc_chip_reset_test(struct hinfc_host *host)
{
	int i = 0;
	unsigned int die_id;
	unsigned int temp;

	/*
	 * winbond W25M02GV flashhas 2 1 gig spi_nand_flash,
	 * different areas controlled by die id
	 */
	die_id = 0;
	temp = 1;
	do {
		/*
		 * if host->opcode.die_code.die_num not initialized
		 * or not a winbond 2G spi nand flash, perform only once
		 */
		if (host->opcode.die_code.die_num > 1) {
			temp = host->opcode.die_code.die_num;
			hi_fmc_dieid_set(host, die_id);
		}
		hinfc_write(host, NAND_CMD_RESET, FMC_CMD);
		/* write config reg, select the nand flash for DMA */
		hinfc_write(host, ((host->chipselect &
			FMC_OP_CFG_CS_MASK) << FMC_OP_CFG_CS_SHIFT), FMC_OP_CFG);
		/*
		 * enable logic
		 * write reg, wait for ready/busy signal to be high for nand flash
		 * send command1 to flash to enable
		 * 0x89
		 */
		if (host->flashtype == NAND_FLASH_TYPE) {
			hinfc_write(host,
				FMC_OP_CMD1_EN | FMC_OP_WAIT_READY_EN | FMC_OP_REG_OP_START,
				FMC_OP);

			if (!hi_reg_status_check_mdelay(host, FMC_OP))
				return 0;
		} else {
			hinfc_write(host, 0x81, FMC_OP);
			hi_reg_status_check(host, FMC_OP);
			while (hi_fmc_get_feature(host->chip, 0xc0, 0xf) & 0x1) {
				i++;
				if (i > FMC_CHECK_STATUS_LOOP_MAX) {
					pr_warn("FMC: reset spi nand flash failed, CS%d!\r\n",
						host->chipselect);
					return 1;
				}
			}
			return 0;
		}
		die_id++;
	} while (die_id < temp);
	return 1;
}

static unsigned int fmc_cmd_ctrl_reset(struct nand_chip *chip)
{
	struct hinfc_host *host = chip->priv;
	unsigned int count = 0;
	unsigned int die_id = 0;
	unsigned int temp = 1;

	do {
		/*
		 * if host->opcode.die_code.die_num not initialized
		 * or not a winbond 2G spi nand flash, perform only once
		 */
		if (host->opcode.die_code.die_num > 1) {
			temp = host->opcode.die_code.die_num;
			hi_fmc_dieid_set(host, die_id);
		}

		hinfc_write(host, NAND_CMD_RESET, FMC_CMD);
		/* write config reg, select the nand flash for DMA */
		hinfc_write(host, ((host->chipselect &
			FMC_OP_CFG_CS_MASK) << FMC_OP_CFG_CS_SHIFT), FMC_OP_CFG);

		/*
		 * enable logic
		 * write reg, wait for ready/busy signal to be high for nand flash
		 * send command1 to flash to enable
		 * 0x89
		 */
		if (host->flashtype == NAND_FLASH_TYPE) {
			hinfc_write(host,
				FMC_OP_CMD1_EN |
				FMC_OP_WAIT_READY_EN |
				FMC_OP_REG_OP_START,
					FMC_OP);

			hi_reg_status_check(host, FMC_OP);
		} else {
			hinfc_write(host,
				FMC_OP_REG_OP_START | FMC_OP_CMD1_EN,
				FMC_OP);
			hi_reg_status_check(host, FMC_OP);

			while (hi_fmc_get_feature(
					chip, SPI_NAND_STATUS_REGISTER, FMC_CMD_GET_FEATURE)
				& 0x1) {
				if (count++ >= FMC_CHECK_STATUS_LOOP_MAX) {
					pr_warn("FMC: reset spi nand flash failed, CS%d!\r\n",
						host->chipselect);
					return 1;
				}
			}
		}
		die_id++;
	} while (die_id < temp);

	return 0;
}

static void fmc_recode_init(struct hinfc_host *host)
{
	/* dfx method, Used to record the number of times that a block is erased */
	unsigned int mtd_size;
	unsigned int erase_cnt_buf_size;

	if (strstr(g_flash_cmd_line, "flashsize=0x10000000") != NULL)
		mtd_size = 0x10000000;
	else if (strstr(g_flash_cmd_line, "flashsize=0x20000000") != NULL)
		mtd_size = 0x20000000;
	else
		mtd_size = 0x8000000;

	erase_cnt_buf_size = g_dfx_blcok_status.block_size * sizeof(unsigned int);
	g_dfx_blcok_status.block_size = mtd_size / host->hw_blocksize;
	g_dfx_blcok_status.page_per_block = host->hw_blocksize / host->hw_pagesize;
	g_dfx_blcok_status.flash_block_erase_time = kzalloc(erase_cnt_buf_size,
		GFP_KERNEL);
	if (g_dfx_blcok_status.flash_block_erase_time != NULL) {
		memset(g_dfx_blcok_status.flash_block_erase_time, 0, erase_cnt_buf_size);
		g_dfx_blcok_status.valid = 1;
	}
}

static void fmc_record_block_status(struct hinfc_host *host)
{
	unsigned int block_index;

	block_index = GET_PAGE_INDEX(host) / g_dfx_blcok_status.page_per_block;
	if ((g_dfx_blcok_status.valid == 1) && (host->command == NAND_CMD_ERASE1)) {
		if (block_index < g_dfx_blcok_status.block_size) {
			g_dfx_blcok_status.block_index = block_index;
			/*
			 * Bits 0 to 30 indicate the number of erasing times, and bit 31
			 * indicates whether the block is a bad block.
			 */
			g_dfx_blcok_status.flash_block_erase_time[block_index] += 1;
		}
	}
}

static void fmc_record_block_bad_status(void)
{
	/* Bit 31 indicates whether the block is a bad block.*/
	if (g_dfx_blcok_status.valid)
		g_dfx_blcok_status.flash_block_erase_time[g_dfx_blcok_status.block_index] |=
			0x80000000;
}

struct fmc_block_status_info *fmc_dfx_get_block_status(void)
{
	if (g_dfx_blcok_status.valid)
		return &g_dfx_blcok_status;
	return NULL;
}
EXPORT_SYMBOL(fmc_dfx_get_block_status);

static void fmc_cmd_ctrl(struct nand_chip *chip, int dat, unsigned int ctrl)
{
	struct hinfc_host *host = chip->priv;
	unsigned int ecc_type;
	unsigned int die_id = 0;
	unsigned int retvalue;

	if (ctrl & NAND_ALE) {
		unsigned int addr_value = 0;
		unsigned int addr_offset = 0;

		if (ctrl & NAND_CTRL_CHANGE) {
			host->addr_cycle = 0x0;
			host->addr_value[0] = 0x0;
			host->addr_value[1] = 0x0;
		}

		addr_offset =  host->addr_cycle << 3;

		if (host->addr_cycle >= FMC_ADDR_CYCLE_MASK) {
			addr_offset = (host->addr_cycle - FMC_ADDR_CYCLE_MASK) << 3;
			addr_value = 1;
		}

		host->addr_value[addr_value] |= (((unsigned int)dat & 0xff) << addr_offset);
		host->addr_cycle++;
	}

	if ((ctrl & NAND_CLE) && (ctrl & NAND_CTRL_CHANGE)) {
		host->command = (unsigned int)dat & 0xff;
		fmc_record_block_status(host);

		switch (host->command) {
		case NAND_CMD_PAGEPROG: /* page program Command Cycle #2 */
			if (host->opcode.die_code.die_num > 1) {
				if (host->addr_value[1] > 0)
					die_id = 1;
				hi_fmc_dieid_set(host, die_id);

				/* device addr cfg reg high byte */
				hinfc_write(host, 0, FMC_ADDRH);
			} else {
				/* device addr cfg reg low 4byte */
				hinfc_write(host, host->addr_value[1], FMC_ADDRH);
			}

			/*
			 * step 1: config the device addr for
			 * reading flash, write op addr reg
			 * device addr cfg reg low 4byte
			 */
			hinfc_write(host, host->addr_value[0] & 0xffff0000, FMC_ADDRL);
			fmc_dma_transfer(host, 1);
			break;
			/* READ PAGE:Command Cycle#2 */
		case NAND_CMD_READSTART:
			if (host->opcode.die_code.die_num > 1) {
				if (host->addr_value[1] > 0)
					die_id = 1;
				hi_fmc_dieid_set(host, die_id);

				/* device addr cfg reg high byte */
				hinfc_write(host, 0, FMC_ADDRH);
			} else {
				/* device addr cfg reg low 4byte */
				hinfc_write(host, host->addr_value[1], FMC_ADDRH);
			}

			hinfc_write(host, FMC_INT_MASK, FMC_INTCLR);
			/* lower-bit addr cfg reg */
			hinfc_write(host, host->addr_value[0] & 0xffff0000, FMC_ADDRL);
			fmc_dma_transfer(host, 0);
			host->uc_er = 0;
			break;
			/* ERASE BLOCK :Command Cycle#2 */
		case NAND_CMD_ERASE2:
			if (host->flashtype == NAND_FLASH_TYPE) {
				/* set low 4 bits of register by the address of device */
				hinfc_write(host, host->addr_value[0], FMC_ADDRL);

				/*
				 * data-length register:you need to process the
				 * length of data in one operation,set the register when
				 * transport data but the direct operation of dma or
				 * AHB bus does not need to configure,only aim at ECC0
				 */
				hinfc_write(host, 1, FMC_DATA_NUM);

				/* the op operate needs configure the CMD register command word */
				hinfc_write(host,
					(NAND_CMD_ERASE2 << 8) | NAND_CMD_ERASE1, FMC_CMD);

				/*
				 * operate configure register:first to select
				 * the FLash device for operating and send byte
				 * of address to FLash
				 */
				hinfc_write(host,
					(((host->chipselect & FMC_OP_CFG_CS_MASK) <<
						FMC_OP_CFG_CS_SHIFT) |
					((3 & FMC_OP_CFG_ADDR_NUM_MASK) <<
						FMC_OP_CFG_ADDR_NUM_SHIFT)),
					FMC_OP_CFG);

				/*
				 * operate register:
				 * send command1 for enable to flash;
				 * write operated address for enable to FLASH;
				 * send command2 to nand flash for enable;
				 * nand flash waits for the signal of ready/busy up for enable;
				 * enables the issue of a command 0x70 to NAND
				 * for reading and reads status from NAND Flash,
				 * the return data write to fm_status part of NANDC
				 * status register, but do NOT write to buffer inside.
				 * logic for enable
				 * 0xdb
				 */
				hinfc_write(host,
					FMC_OP_CMD1_EN | FMC_OP_ADDR_EN |
					FMC_OP_CMD2_EN | FMC_OP_WAIT_READY_EN |
					FMC_OP_READ_STATUS_EN | FMC_OP_REG_OP_START,
					FMC_OP);
				hi_reg_status_check(host, FMC_OP);
			} else {
				if (host->opcode.die_code.die_num > 1) {
					/*
					 * winbond FLASH has 2 sub flash,
					 * judge according to addr_value
					 */
					if (host->addr_value[0] < 1024 * 64) {
						die_id = 0;
					} else {
						die_id = 1;
						host->addr_value[0] =
							host->addr_value[0] - (1024 * 64);
					}

					hi_fmc_dieid_set(host, die_id);
				}

				hinfc_write(host, FMC_CMD_WRITE_ENABLE, FMC_CMD);
				hinfc_write(
					host,
					(host->chipselect &
						FMC_OP_CFG_CS_MASK) << FMC_OP_CFG_CS_SHIFT,
						FMC_OP_CFG);
				hinfc_write(host, FMC_OP_REG_OP_START | FMC_OP_CMD1_EN, FMC_OP);
				/*
				 * receive the next command when operate
				 * is completed, the logic can only be 0,
				 * which means logic is complete
				 */
				hi_reg_status_check(host, FMC_OP);

				hinfc_write(host, host->opcode.erase_code, FMC_CMD);
				hinfc_write(host, host->addr_value[0], FMC_ADDRL);
				hinfc_write(host,
					(((host->chipselect & FMC_OP_CFG_CS_MASK) <<
						FMC_OP_CFG_CS_SHIFT) |
					((3 & FMC_OP_CFG_ADDR_NUM_MASK) <<
						FMC_OP_CFG_ADDR_NUM_SHIFT)),
					FMC_OP_CFG);
				hinfc_write(host,
					FMC_OP_REG_OP_START | FMC_OP_ADDR_EN | FMC_OP_CMD1_EN,
					FMC_OP);
				/*
				 * receive the next command when operate
				 * is completed, the logic can only be 0,
				 * which means logic is complete
				 */
				hi_reg_status_check(host, FMC_OP);
				hinfc_write(host, FMC_CMD_GET_FEATURE, FMC_CMD);
				hinfc_write(host,
					FMC_OP_REG_OP_START|FMC_OP_READ_STATUS_EN, FMC_OP);
				hi_reg_status_check(host, FMC_OP);

				while (hinfc_read(host, FMC_FLASH_INFO) & 0x1) {
					hinfc_write(host,
						FMC_OP_REG_OP_START|FMC_OP_READ_STATUS_EN, FMC_OP);
					hi_reg_status_check(host, FMC_OP);
				}

				if (hinfc_read(host, FMC_FLASH_INFO) & 0x4) {
					pr_err("FMC: device erase fail\n");
					fmc_record_block_bad_status();
					return;
				}
			}

			/* grand total the number of nand flash erasing */
			g_nand_ewetimes.ui_erasetimes++;
			break;
		case NAND_CMD_READID: /* READ ID */
			/* clear NAND read addr */
			memset((unsigned char *)(chip->legacy.IO_ADDR_R), 0, 0x10);
			ecc_type = hi_fmc_ecctype_get(host);
			hi_fmc_ecctype_set(host, 0); /* need to close ecc */
			if (host->flashtype == NAND_FLASH_TYPE) {
				hinfc_write(host, NAND_CMD_READID, FMC_CMD);
				hinfc_write(host, 0, FMC_ADDRL);
				hinfc_write(host, 5, FMC_DATA_NUM);
				/* select cs0 to send byte of FLash address */
				hinfc_write(host,
					((host->chipselect & FMC_OP_CFG_CS_MASK) <<
						FMC_OP_CFG_CS_SHIFT) |
					1 << FMC_OP_CFG_ADDR_NUM_SHIFT,
					FMC_OP_CFG);
				/*
				 * logic for enable
				 * enable to read from FLash
				 * write operated address for enable to FLASH
				 * send command1 for enable to flash
				 * 0xc5
				 */
				hinfc_write(host,
					FMC_OP_CMD1_EN | FMC_OP_ADDR_EN |
					FMC_OP_READ_DATA_EN | FMC_OP_REG_OP_START,
					FMC_OP);
			} else {
				hinfc_write(host, FMC_READ_ID_SPI, FMC_CMD);
				hinfc_write(host, 5, FMC_DATA_NUM);
				hinfc_write(host,
					((host->chipselect & FMC_OP_CFG_CS_MASK) <<
						FMC_OP_CFG_CS_SHIFT) |
					(0x1 & FMC_OP_CFG_DUMMY_NUM_MASK),
					FMC_OP_CFG);
				hinfc_write(host,
					FMC_OP_REG_OP_START | FMC_OP_READ_DATA_EN |
					FMC_OP_CMD1_EN | FMC_OP_DUMMY_EN,
					FMC_OP);
			}

			host->addr_cycle = 0x0;

			hi_reg_status_check(host, FMC_OP);
			/* ECC restore */
			hi_fmc_ecctype_set(host, ecc_type);
			break;
		case NAND_CMD_STATUS: /* READ STATUS */
			/* read addr of nand is cleared by default */
			memset((unsigned char *)(chip->legacy.IO_ADDR_R), 0, 0x10);
			if (host->flashtype == NAND_FLASH_TYPE) {
				ecc_type = hi_fmc_ecctype_get(host);
				hi_fmc_ecctype_set(host, 0); /* need to close ecc */
				hinfc_write(host, NAND_CMD_STATUS, FMC_CMD);

				/*
				 * the NAND FLASH device operated by DMA
				 * which is used for operating configure register
				 */
				hinfc_write(host,
					((host->chipselect & FMC_OP_CFG_CS_MASK) <<
						FMC_OP_CFG_CS_SHIFT),
					FMC_OP_CFG);
				hinfc_write(host, 1, FMC_DATA_NUM);
				/*
				 * logic for enable
				 * enable to read from FLash
				 * send command1 for enable to flash
				 * 0X8D
				 */
				hinfc_write(host,
					FMC_OP_CMD1_EN | FMC_OP_WAIT_READY_EN |
					FMC_OP_READ_DATA_EN | FMC_OP_REG_OP_START,
					FMC_OP);
				hi_reg_status_check(host, FMC_OP);
				/* ECC restore */
				hi_fmc_ecctype_set(host, ecc_type);
			} else {
				/* c0 is the status register for SPI NAND Flash */
				hi_fmc_get_feature(chip, SPI_NAND_STATUS_REGISTER,
					FMC_CMD_GET_FEATURE);
				/*
				 * The meaning of the register bits in SPI Nand Flash
				 * and the register in Nand Flash are not the same
				 * In order to reflect the outside world, the register
				 * bit here. At present, only modify the Operation
				 * state and Write enable latch, the follow-up is useful
				 * to note the changes
				 */
				*((unsigned int *)chip->legacy.IO_ADDR_R) =
					(((~(*((unsigned int *)chip->legacy.IO_ADDR_R) &
							0x1)) << 6) &
						0x40) |
					0x80;
			}
			break;
			/* Command Cycle #1:program ,erase,read */
		case NAND_CMD_SEQIN:
		case NAND_CMD_ERASE1:
		case NAND_CMD_READ0:
			break;
			/* reset */
		case NAND_CMD_RESET:
			retvalue = fmc_cmd_ctrl_reset(chip);
			if (retvalue != 0)
				return;
			break;
		default:
			break;
		}
	}

	/* pass pagesize and ecctype to kernel when startup. */
	if ((dat == NAND_CMD_NONE) && host->addr_cycle) {
		if (host->command == NAND_CMD_SEQIN || host->command == NAND_CMD_READ0 ||
			host->command == NAND_CMD_READID) {
			host->offset = 0x0;
			host->column = (host->addr_value[0] & 0xffff);
		}
	}
}

static int fmc_dev_ready(struct nand_chip *chip)
{
	return 0x1;
}

static void fmc_select_chip(struct nand_chip *chip, int chipselect)
{
	struct hinfc_host *host = chip->priv;

	if (chipselect < 0)
		return;

	if (chipselect > CONFIG_FMC_MAX_CHIP)
		DBG_BUG("invalid chipselect: %d\n", chipselect);

	if (host->flashtype == SPI_NAND_FLASH_TYPE) {
		if (chipselect == 0)
			host->chipselect = 1;
		else
			host->chipselect = 0;
	} else {
		host->chipselect = chipselect;
	}
}

static void fmc_read_buf(struct nand_chip *chip, uint8_t *buf, int len)
{
	struct hinfc_host *host = chip->priv;

	memcpy(buf, host->buffer + host->column + host->offset, len);
	host->offset += len;

	if (hinfc_read(host, FMC_INT) & 0x08)
		g_nand_ewetimes.ui_unco_ecc_err++;

	if (hinfc_read(host, FMC_INT) & 0x04)
		g_nand_ewetimes.ui_co_ecc_err++;
}
/// ### ///
#ifdef CONFIG_HINFC301_HARDWARE_PAGESIZE_ECC

static int nand_ecc_2K_4bits_ooblayout_free(
	struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion)
{
	if (section > 1)
		return -ERANGE;
	oobregion->offset = 2;
	oobregion->length = 30;
	return 0;
}

static int nand_ecc_2K_8bits_ooblayout_free(
	struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion)
{
	if (section > 1)
		return -ERANGE;
	oobregion->offset = 2;
	oobregion->length = 6;
	return 0;
}

static struct mtd_ooblayout_ops nand_ecc_2K_4bits_ooblayout_ops = {
	.free = nand_ecc_2K_4bits_ooblayout_free,
};

static struct mtd_ooblayout_ops nand_ecc_2K_8bits_ooblayout_ops = {
	.free = nand_ecc_2K_8bits_ooblayout_free,
};

#ifdef CONFIG_RTOS_STORAGE_FMC_8BIT_ECC
static struct mtd_ooblayout_ops nand_ecc_2K_24bits_ooblayout_ops = {
	.free = nand_ecc_2K_4bits_ooblayout_free,
};
#endif
static struct mtd_ooblayout_ops nand_ecc_4K_24bits_ooblayout_ops = {
	.free = nand_ecc_2K_4bits_ooblayout_free,
};
#endif

static struct fmc_page_ecc_info page_page_ecc_5117_info[] = {
#ifdef CONFIG_HINFC301_HARDWARE_PAGESIZE_ECC
	{pt_fmc_pagesize_2K, et_ecc_5117_8bit, 64, &nand_ecc_2K_4bits_ooblayout_ops},
#ifdef CONFIG_RTOS_STORAGE_FMC_8BIT_ECC
	{pt_fmc_pagesize_2K, et_ecc_5117_16bit, 64, &nand_ecc_2K_8bits_ooblayout_ops},
	{pt_fmc_pagesize_2K, et_ecc_5117_24bit, 128, &nand_ecc_2K_24bits_ooblayout_ops},
#else
	{pt_fmc_pagesize_2K, et_ecc_5117_16bit, 128, &nand_ecc_2K_8bits_ooblayout_ops},
#endif
	{pt_fmc_pagesize_4K, et_ecc_5117_24bit, 256, &nand_ecc_4K_24bits_ooblayout_ops},
#endif
	{0, 0, 0, NULL},
};


/* used the best correct arithmetic. */
struct fmc_page_ecc_info *fmc_get_best_ecc(struct mtd_info *mtd)
{
	struct fmc_page_ecc_info *best = NULL;
	struct fmc_page_ecc_info *info = page_page_ecc_5117_info;

	for (; info->layout; info++) {
		if (get_pagesize(info->pagetype) != mtd->writesize)
			continue;

		if (mtd->oobsize < info->oobsize)
			continue;

		if (!best || (best->ecctype < info->ecctype))
			best = info;
	}

	if (!best) {
		DBG_BUG("not support this pagesize(%d) and oobsize(%d).\n",
			mtd->writesize, mtd->oobsize);
	}

	return best;
}

/* force the pagesize and ecctype */
struct fmc_page_ecc_info *fmc_force_ecc(struct mtd_info *mtd, enum page_fmc_type pagetype,
	unsigned int ecctype, char *cfgmsg, int allow_pagediv)
{
	int pagesize;
	struct fmc_page_ecc_info *fit = NULL;
	struct fmc_page_ecc_info *info = page_page_ecc_5117_info;

	for (; info->layout; info++) {
		if (info->pagetype == pagetype && info->ecctype == ecctype) {
			fit = info;
			break;
		}
	}

	if (!fit) {
		DBG_BUG("system not support this nand %s: pagesize:%s, ecctype:%s\n",
			cfgmsg, get_pagesize_str(pagetype), get_ecctype_str(ecctype));
		return NULL;
	}

	pagesize = get_pagesize(pagetype);
	if ((pagesize != mtd->writesize) && (pagesize > mtd->writesize || !allow_pagediv)) {
		DBG_BUG("%s is inconsistent, config pagesize %d, ",
			cfgmsg, pagesize);
		DBG_BUG("but the nand chip pageszie is %d\n", mtd->writesize);
		return NULL;
	}

	if (fit->oobsize > mtd->oobsize) {
		DBG_BUG("%s is inconsistent, config %s require oobsize(%d),",
			cfgmsg, get_ecctype_str(ecctype), fit->oobsize);
		DBG_BUG("but the nand chip oobsize is %d, littler than config require.\n",
			mtd->oobsize);
		return NULL;
	}

	return fit;
}

static void fmc_ecc_probe(struct mtd_info *mtd, struct nand_chip *chip)
{
	const char *start_type = "unknown";
	struct fmc_page_ecc_info *best = NULL;
	struct hinfc_host *host = chip->priv;

#ifdef CONFIG_FMC_AUTO_PAGESIZE_ECC
	best = fmc_get_best_ecc(mtd);
	start_type = "Auto";
#endif

#ifdef CONFIG_HINFC301_HARDWARE_PAGESIZE_ECC
	/* oobsize need be resized which is not in nand table */
	if ((g_default_oob_size == UINT_MAX) && (mtd->writesize == FMC_4K))
		mtd->oobsize = 256;

	/* 8bit ecc,2k page size */
	host->NFC_CON = hinfc_read(host, FMC_CFG);
	best = fmc_force_ecc(mtd,
		((host->NFC_CON >> FMC_CFG_PAGEISZE_SHIFT) & FMC_CFG_PAGESIZE_MASK),
		((host->NFC_CON >> FMC_CFG_ECCTYPE_SHIFT) & FMC_CFG_ECCTYPE_MASK),
		"hardware config", 0);
	start_type = "Hardware";
#endif

	if (!best)
		DBG_BUG("Please select nand flash pagesize and ecctype!\n");

	if (best->ecctype != et_ecc_5117_none)
		mtd->oobsize = best->oobsize;

	//chip->ecc.layout = best->layout;
	mtd->ooblayout = best->layout;
	host->ecctype = best->ecctype;
	host->pagesize = get_pagesize(best->pagetype);
	host->dma_oob = host->dma_buffer + host->pagesize;

	if (mtd->writesize > NAND_MAX_PAGESIZE || mtd->oobsize > NAND_MAX_OOBSIZE) {
		DBG_BUG("kernel not support this NAND.");
		DBG_BUG("please increase NAND_MAX_PAGESIZE and NAND_MAX_OOBSIZE.\n");
	}

	if (mtd->writesize != host->pagesize) {
		unsigned int shift = 0;
		unsigned int writesize = mtd->writesize;

		while (writesize > host->pagesize) {
			writesize >>= 1;
			shift++;
		}

		mtd->size = mtd->size >> shift;
		mtd->erasesize = mtd->erasesize >> shift;
		mtd->writesize = host->pagesize;
		pr_info("Nand divide into 1/%u\n", (1 << shift));
	}

	fmc_flash_feature_init(mtd);
}

int fmc_nand_init(struct hinfc_host *host, struct nand_chip *chip)
{
	unsigned int ui_reg_addr;
	unsigned int reg_value;
	unsigned int *ui_reg_value = NULL;
	unsigned int flash_type = 0, i;
	/* Power configuration word */
	unsigned int flash_type_reg[FLASH_TYPE_REG_NUM] = {0x1494009c, 0x149400a0,
		0x149400a4, 0x149400a8, 0x149400ac, 0x149400b0, 0x149400e8, 0x149400e0};
	/*
	 * 5117P power-on configuration word has
	 * been adjusted, each register bits [6] for stitching
	 */
	unsigned int flash_type_reg_5117p[FLASH_TYPE_5117P_REG_NUM] = {0x14940010,
		0x14940014, 0x14940018, 0x1494009c};
	unsigned int *flash_value = NULL;

	enum page_fmc_type pagetype;
	enum block_fmc_type blocktype;
	uint32_t reg_val;

	chip->priv = host;
	chip->legacy.cmd_ctrl = fmc_cmd_ctrl;
	chip->legacy.dev_ready = fmc_dev_ready;
	chip->legacy.select_chip = fmc_select_chip;
	chip->legacy.read_byte = hi_read_byte;
	//chip->legacy.read_word = hi_read_word;
	chip->legacy.write_buf = hi_write_buf;
	chip->legacy.read_buf = fmc_read_buf;
	chip->legacy.chip_delay = FMC_CHIP_DELAY;
	chip->options = NAND_SKIP_BBTSCAN;
	//chip->ecc.layout = NULL;
	chip->ecc.engine_type = NAND_ECC_ENGINE_TYPE_NONE;
	host->chip = chip;
	host->addr_cycle = 0;
	host->addr_value[0] = 0;
	host->addr_value[1] = 0;

	ui_reg_addr = 0x10100800;  /* chiptype addr */

	ui_reg_value = (unsigned int *)ioremap(ui_reg_addr, sizeof(unsigned int));
	if (!ui_reg_value)
		return 1;

	reg_val = readl(ui_reg_value);
	if ((reg_val & CHIP_ID_SERIAL_VERSION_MASK) == CHIP_ID_SD5117P) {
		for (i = 0; i < FLASH_TYPE_5117P_REG_NUM; i++) {
			flash_value = (unsigned int *)ioremap(
				flash_type_reg_5117p[i], sizeof(unsigned int));
			if (!flash_value) {
				iounmap(ui_reg_value);
				return 1;
			}
			/* 6th bit is valid value of flash type */
			flash_type |= ((readl(flash_value) & 0x40) >> 6) << i;
			iounmap(flash_value);
		}

		if (flash_type <= FLASH_TYPE_REG_NUM) {
			host->flashtype = SPI_NAND_FLASH_TYPE;
			host->chipselect = 1;
		} else if ((flash_type > (FLASH_TYPE_REG_NUM - 1)) &&
			(flash_type <= (FLASH_TYPE_REG_NUM + 1))) {
			host->flashtype = NAND_FLASH_TYPE;
			host->chipselect = 0;
		}
	} else if ((reg_val & CHIP_ID_SERIAL_VERSION_MASK) == CHIP_ID_SD5117H) {
		for (i = 0; i < FLASH_TYPE_REG_NUM; i++) {
			flash_value = (unsigned int *)ioremap(
				flash_type_reg[i], sizeof(unsigned int));
			if (!flash_value) {
				iounmap(ui_reg_value);
				return 1;
			}
			/*
			 * 6th bit is valid value of flash type,
			 * flash type is stored by bit whether it's supported
			 */
			flash_type |= ((readl(flash_value) & 0x40) >> 6) << i;
			iounmap(flash_value);
		}

		/* get flash type according to the shifted flash_type */
		if (flash_type <= 0x28) {
			host->flashtype = NAND_FLASH_TYPE;
			host->chipselect = 0;
			pr_info("NAND_FLASH_TYPE\r\n");
		} else if (flash_type > 0x28 && flash_type <= 0x90) {
			host->flashtype = SPI_NAND_FLASH_TYPE;
			host->chipselect = 1;
			pr_info("SPI_NAND_FLASH_TYPE\r\n");
		} else if (flash_type > 0x90 && flash_type <= 0x92) {
			pr_info("BOOT_FROM_SPI_NOR");
		} else {
			host->flashtype = SPI_NAND_FLASH_TYPE;
			host->chipselect = 1;
			pr_info("SPI_NAND_FLASH_TYPE......\r\n");
		}
	} else {
		if (strstr(g_flash_cmd_line, "flash_chip=nand") != NULL) {
			host->flashtype = NAND_FLASH_TYPE;
		} else if (strstr(g_flash_cmd_line, "flash_chip=spinand") != NULL) {
			host->flashtype = SPI_NAND_FLASH_TYPE;
		} else {
			host->flashtype = SPI_NAND_FLASH_TYPE;
			pr_info("default :SPI_NAND_FLASH_TYPE\r\n");
		}

		if (strstr(g_flash_cmd_line, "flash_cs=1") != NULL) {
			host->chipselect = 1;
		} else if (strstr(g_flash_cmd_line, "flash_cs=0") != NULL) {
			host->chipselect = 0;
		} else {
			host->chipselect = 1;
			pr_info("default : CS = 1\r\n");
		}
	}

	iounmap(ui_reg_value);
	reg_value = hinfc_read(host, FMC_CFG);
	/* nor-flash and nandflash FMC_CFG reg init separately */
	if (host->flashtype == NAND_FLASH_TYPE) {
		/* FMC operate way:normal way,FLash type:NAND */
		reg_value &= ~0x6;
		reg_value |= 0x4;
		hinfc_write(host, reg_value | 0x1, FMC_CFG);

		/* read/write register which named pulse width configure register */
		hinfc_write(host, 0x375, PND_PWIDTH_CFG);
	} else {
		reg_value &= ~0x6;
		reg_value |= 0x2;
	}
	hinfc_write(host, reg_value|0x1, FMC_CFG);

	/* hardware config */
	pagetype = (hinfc_read(host, FMC_CFG) >> FMC_CFG_PAGEISZE_SHIFT) & FMC_CFG_PAGESIZE_MASK;
	host->hw_pagesize = get_pagesize(pagetype);

	/* when boots, it is the width of NAND FLash bus way */
	blocktype = (hinfc_read(host, FMC_CFG) >> FMC_CFG_BLOCKSZE_SHIFT) & FMC_CFG_PAGESIZE_MASK;
	host->hw_blocksize = get_blocksize(blocktype) * host->hw_pagesize;
	host->buffer = dma_alloc_coherent(host->dev, (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE),
		&host->dma_buffer, GFP_KERNEL);

	if (!host->buffer)
		return 1;
	/*
	 * FMC_BUFFER_BASE_ADDRESS_LEN is the length of FMC_MEM_BASE application starts
	 * it would not be out of range
	 */
	memset((char *)chip->legacy.IO_ADDR_R, 0xff, FMC_BUFFER_BASE_ADDRESS_LEN);
	memset(host->buffer, 0xff, (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE));

	nand_base_oob_resize = fmc_ecc_probe;
	fmc_recode_init(host);

	return 0;
}

MODULE_IMPORT_NS(HW_RTOS_NS);
